home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / prgtools / mint / mgr / sparcmgr / demo2.zoo / demo / ex / ex_vget.c < prev    next >
Encoding:
C/C++ Source or Header  |  1987-04-24  |  13.6 KB  |  698 lines

  1. /*
  2.  * Copyright (c) 1980 Regents of the University of California.
  3.  * All rights reserved.  The Berkeley software License Agreement
  4.  * specifies the terms and conditions for redistribution.
  5.  */
  6.  
  7. #ifndef lint
  8. static char *sccsid = "@(#)ex_vget.c    6.9 (Berkeley) 3/9/87; 1.2 (Bellcore)    87/04/24";
  9. #endif not lint
  10.  
  11. #include "ex.h"
  12. #include "ex_tty.h"
  13. #include "ex_vis.h"
  14.  
  15. /*
  16.  * Input routines for open/visual.
  17.  * We handle upper case only terminals in visual and reading from the
  18.  * echo area here as well as notification on large changes
  19.  * which appears in the echo area.
  20.  */
  21.  
  22. /*
  23.  * Return the key.
  24.  */
  25. ungetkey(c)
  26.     int c;        /* mjm: char --> int */
  27. {
  28.  
  29.     if (Peek_key != ATTN)
  30.         Peek_key = c;
  31. }
  32.  
  33. /*
  34.  * Return a keystroke, but never a ^@.
  35.  */
  36. getkey()
  37. {
  38.     register int c;        /* mjm: char --> int */
  39.  
  40.     do {
  41.         c = getbr();
  42.         if (c==0)
  43.             beep();
  44.     } while (c == 0);
  45.     return (c);
  46. }
  47.  
  48. /*
  49.  * Tell whether next keystroke would be a ^@.
  50.  */
  51. peekbr()
  52. {
  53.  
  54.     Peek_key = getbr();
  55.     return (Peek_key == 0);
  56. }
  57.  
  58. short    precbksl;
  59. jmp_buf    readbuf;
  60. int    doingread = 0;
  61.  
  62. /*
  63.  * Get a keystroke, including a ^@.
  64.  * If an key was returned with ungetkey, that
  65.  * comes back first.  Next comes unread input (e.g.
  66.  * from repeating commands with .), and finally new
  67.  * keystrokes.
  68.  *
  69.  * The hard work here is in mapping of \ escaped
  70.  * characters on upper case only terminals.
  71.  */
  72. getbr()
  73. {
  74.     char ch;
  75.     register int c, d;
  76.     register char *colp;
  77. #define BEEHIVE
  78. #ifdef BEEHIVE
  79.     static char Peek2key;
  80. #endif
  81.     extern short slevel, ttyindes;
  82.  
  83. getATTN:
  84.     if (Peek_key) {
  85.         c = Peek_key;
  86.         Peek_key = 0;
  87.         return (c);
  88.     }
  89. #ifdef BEEHIVE
  90.     if (Peek2key) {
  91.         c = Peek2key;
  92.         Peek2key = 0;
  93.         return (c);
  94.     }
  95. #endif
  96.     if (vglobp) {
  97.         if (*vglobp)
  98.             return (lastvgk = *vglobp++);
  99.         lastvgk = 0;
  100.         return (ESCAPE);
  101.     }
  102.     if (vmacp) {
  103.         if (*vmacp)
  104.             return(*vmacp++);
  105.         /* End of a macro or set of nested macros */
  106.         vmacp = 0;
  107.         if (inopen == -1)    /* don't screw up undo for esc esc */
  108.             vundkind = VMANY;
  109.         inopen = 1;    /* restore old setting now that macro done */
  110.         vch_mac = VC_NOTINMAC;
  111.     }
  112.     flusho();
  113. again:
  114.     if (setjmp(readbuf))
  115.         goto getATTN;
  116.     doingread = 1;
  117. #ifndef    vms
  118.     c = read(slevel == 0 ? 0 : ttyindes, &ch, 1);
  119. #else
  120.     c = vms_read(slevel == 0 ? 0 : ttyindes, &ch, 1);
  121. #endif
  122.     doingread = 0;
  123.     if (c != 1) {
  124.         if (errno == EINTR)
  125.             goto getATTN;
  126.         error("Input read error");
  127.     }
  128.     c = ch & TRIM;
  129. #ifdef BEEHIVE
  130.     if (XB && slevel==0 && c == ESCAPE) {
  131.         if (read(0, &Peek2key, 1) != 1)
  132.             goto getATTN;
  133.         Peek2key &= TRIM;
  134.         switch (Peek2key) {
  135.         case 'C':    /* SPOW mode sometimes sends \EC for space */
  136.             c = ' ';
  137.             Peek2key = 0;
  138.             break;
  139.         case 'q':    /* f2 -> ^C */
  140.             c = CTRL(c);
  141.             Peek2key = 0;
  142.             break;
  143.         case 'p':    /* f1 -> esc */
  144.             Peek2key = 0;
  145.             break;
  146.         }
  147.     }
  148. #endif
  149.  
  150. #ifdef UCVISUAL
  151.     /*
  152.      * The algorithm here is that of the UNIX kernel.
  153.      * See the description in the programmers manual.
  154.      */
  155.     if (UPPERCASE) {
  156.         if (isupper(c))
  157.             c = tolower(c);
  158.         if (c == '\\') {
  159.             if (precbksl < 2)
  160.                 precbksl++;
  161.             if (precbksl == 1)
  162.                 goto again;
  163.         } else if (precbksl) {
  164.             d = 0;
  165.             if (islower(c))
  166.                 d = toupper(c);
  167.             else {
  168.                 colp = "({)}!|^~'~";
  169.                 while (d = *colp++)
  170.                     if (d == c) {
  171.                         d = *colp++;
  172.                         break;
  173.                     } else
  174.                         colp++;
  175.             }
  176.             if (precbksl == 2) {
  177.                 if (!d) {
  178.                     Peek_key = c;
  179.                     precbksl = 0;
  180.                     c = '\\';
  181.                 }
  182.             } else if (d)
  183.                 c = d;
  184.             else {
  185.                 Peek_key = c;
  186.                 precbksl = 0;
  187.                 c = '\\';
  188.             }
  189.         }
  190.         if (c != '\\')
  191.             precbksl = 0;
  192.     }
  193. #endif
  194. #ifdef TRACE
  195.     if (trace) {
  196.         if (!techoin) {
  197.             tfixnl();
  198.             techoin = 1;
  199.             fprintf(trace, "*** Input: ");
  200.         }
  201.         tracec(c);
  202.     }
  203. #endif
  204.     lastvgk = 0;
  205.     return (c);
  206. }
  207.  
  208. /*
  209.  * Get a key, but if a delete, quit or attention
  210.  * is typed return 0 so we will abort a partial command.
  211.  */
  212. getesc()
  213. {
  214.     register int c;
  215.  
  216.     c = getkey();
  217.     switch (c) {
  218.  
  219.     case CTRL(v):
  220.     case CTRL(q):
  221.         c = getkey();
  222.         return (c);
  223.  
  224.     case ATTN:
  225.     case QUIT:
  226.         ungetkey(c);
  227.         return (0);
  228.  
  229.     case ESCAPE:
  230.         return (0);
  231.     }
  232.     return (c);
  233. }
  234.  
  235. /*
  236.  * Peek at the next keystroke.
  237.  */
  238. peekkey()
  239. {
  240.  
  241.     Peek_key = getkey();
  242.     return (Peek_key);
  243. }
  244.  
  245. /*
  246.  * Read a line from the echo area, with single character prompt c.
  247.  * A return value of 1 means the user blewit or blewit away.
  248.  */
  249. readecho(c)
  250.     char c;
  251. {
  252.     register char *sc = cursor;
  253.     register int (*OP)();
  254.     bool waste;
  255.     register int OPeek;
  256.  
  257.     if (WBOT == WECHO)
  258.         vclean();
  259.     else
  260.         vclrech(0);
  261.     splitw++;
  262.     vgoto(WECHO, 0);
  263.     ex_putchar(c);
  264.     vclreol();
  265.     vgoto(WECHO, 1);
  266.     cursor = linebuf; linebuf[0] = 0; genbuf[0] = c;
  267.     if (peekbr()) {
  268.         if (!INS[0] || (INS[0] & (QUOTE|TRIM)) == OVERBUF)
  269.             goto blewit;
  270.         vglobp = INS;
  271.     }
  272.     OP = Pline; Pline = normline;
  273.     ignore(vgetline(0, genbuf + 1, &waste, c));
  274.     if (Outchar == termchar)
  275.         ex_putchar('\n');
  276.     vscrap();
  277.     Pline = OP;
  278.     if (Peek_key != ATTN && Peek_key != QUIT && Peek_key != CTRL(h)) {
  279.         cursor = sc;
  280.         vclreol();
  281.         return (0);
  282.     }
  283. blewit:
  284.     OPeek = Peek_key==CTRL(h) ? 0 : Peek_key; Peek_key = 0;
  285.     splitw = 0;
  286.     vclean();
  287.     vshow(dot, NOLINE);
  288.     vnline(sc);
  289.     Peek_key = OPeek;
  290.     return (1);
  291. }
  292.  
  293. /*
  294.  * A complete command has been defined for
  295.  * the purposes of repeat, so copy it from
  296.  * the working to the previous command buffer.
  297.  */
  298. setLAST()
  299. {
  300.  
  301.     if (vglobp || vmacp)
  302.         return;
  303.     lastreg = vreg;
  304.     lasthad = Xhadcnt;
  305.     lastcnt = Xcnt;
  306.     *lastcp = 0;
  307.     CP(lastcmd, workcmd);
  308. }
  309.  
  310. /*
  311.  * Gather up some more text from an insert.
  312.  * If the insertion buffer oveflows, then destroy
  313.  * the repeatability of the insert.
  314.  */
  315. addtext(cp)
  316.     char *cp;
  317. {
  318.  
  319.     if (vglobp)
  320.         return;
  321.     addto(INS, cp);
  322.     if ((INS[0] & (QUOTE|TRIM)) == OVERBUF)
  323.         lastcmd[0] = 0;
  324. }
  325.  
  326. setDEL()
  327. {
  328.  
  329.     ex_setBUF(DEL);
  330. }
  331.  
  332. /*
  333.  * Put text from cursor upto wcursor in BUF.
  334.  */
  335. ex_setBUF(BUF)
  336.     register char *BUF;
  337. {
  338.     register int c;
  339.     register char *wp = wcursor;
  340.  
  341.     c = *wp;
  342.     *wp = 0;
  343.     BUF[0] = 0;
  344.     addto(BUF, cursor);
  345.     *wp = c;
  346. }
  347.  
  348. addto(buf, str)
  349.     register char *buf, *str;
  350. {
  351.  
  352.     if ((buf[0] & (QUOTE|TRIM)) == OVERBUF)
  353.         return;
  354.     if (strlen(buf) + strlen(str) + 1 >= VBSIZE) {
  355.         buf[0] = OVERBUF;
  356.         return;
  357.     }
  358.     ignore(strcat(buf, str));
  359. }
  360.  
  361. /*
  362.  * Note a change affecting a lot of lines, or non-visible
  363.  * lines.  If the parameter must is set, then we only want
  364.  * to do this for open modes now; return and save for later
  365.  * notification in visual.
  366.  */
  367. noteit(must)
  368.     bool must;
  369. {
  370.     register int sdl = destline, sdc = destcol;
  371.  
  372.     if (notecnt < 2 || !must && state == VISUAL)
  373.         return (0);
  374.     splitw++;
  375.     if (WBOT == WECHO)
  376.         vmoveitup(1, 1);
  377.     vigoto(WECHO, 0);
  378.     ex_printf("%d %sline", notecnt, notesgn);
  379.     if (notecnt > 1)
  380.         ex_putchar('s');
  381.     if (*notenam) {
  382.         ex_printf(" %s", notenam);
  383.         if (*(strend(notenam) - 1) != 'e')
  384.             ex_putchar('e');
  385.         ex_putchar('d');
  386.     }
  387.     vclreol();
  388.     notecnt = 0;
  389.     if (state != VISUAL)
  390.         vcnt = vcline = 0;
  391.     splitw = 0;
  392.     if (state == ONEOPEN || state == CRTOPEN)
  393.         vup1();
  394.     destline = sdl; destcol = sdc;
  395.     return (1);
  396. }
  397.  
  398. /*
  399.  * Rrrrringgggggg.
  400.  * If possible, use flash (VB).
  401.  */
  402. beep()
  403. {
  404.  
  405.     if (VB)
  406.         vputp(VB, 0);
  407.     else
  408.         vputc(CTRL(g));
  409. }
  410.  
  411. /*
  412.  * Map the command input character c,
  413.  * for keypads and labelled keys which do cursor
  414.  * motions.  I.e. on an adm3a we might map ^K to ^P.
  415.  * DM1520 for example has a lot of mappable characters.
  416.  */
  417.  
  418. map(c,maps)
  419.     register int c;
  420.     register struct maps *maps;
  421. {
  422.     register int d;
  423.     register char *p, *q;
  424.     char b[10];    /* Assumption: no keypad sends string longer than 10 */
  425.  
  426.     /*
  427.      * Mapping for special keys on the terminal only.
  428.      * BUG: if there's a long sequence and it matches
  429.      * some chars and then misses, we lose some chars.
  430.      *
  431.      * For this to work, some conditions must be met.
  432.      * 1) Keypad sends SHORT (2 or 3 char) strings
  433.      * 2) All strings sent are same length & similar
  434.      * 3) The user is unlikely to type the first few chars of
  435.      *    one of these strings very fast.
  436.      * Note: some code has been fixed up since the above was laid out,
  437.      * so conditions 1 & 2 are probably not required anymore.
  438.      * However, this hasn't been tested with any first char
  439.      * that means anything else except escape.
  440.      */
  441. #ifdef MDEBUG
  442.     if (trace)
  443.         fprintf(trace,"map(%c): ",c);
  444. #endif
  445.     /*
  446.      * If c==0, the char came from getesc typing escape.  Pass it through
  447.      * unchanged.  0 messes up the following code anyway.
  448.      */
  449.     if (c==0)
  450.         return(0);
  451.  
  452.     b[0] = c;
  453.     b[1] = 0;
  454.     for (d=0; maps[d].mapto; d++) {
  455. #ifdef MDEBUG
  456.         if (trace)
  457.             fprintf(trace,"\ntry '%s', ",maps[d].cap);
  458. #endif
  459.         if (p = maps[d].cap) {
  460.             for (q=b; *p; p++, q++) {
  461. #ifdef MDEBUG
  462.                 if (trace)
  463.                     fprintf(trace,"q->b[%d], ",q-b);
  464. #endif
  465.                 if (*q==0) {
  466.                     /*
  467.                      * Is there another char waiting?
  468.                      *
  469.                      * This test is oversimplified, but
  470.                      * should work mostly. It handles the
  471.                      * case where we get an ESCAPE that
  472.                      * wasn't part of a keypad string.
  473.                      */
  474.                     if ((c=='#' ? peekkey() : fastpeekkey()) == 0) {
  475. #ifdef MDEBUG
  476.                         if (trace)
  477.                             fprintf(trace,"fpk=0: will return '%c'",c);
  478. #endif
  479.                         /*
  480.                          * Nothing waiting.  Push back
  481.                          * what we peeked at & return
  482.                          * failure (c).
  483.                          *
  484.                          * We want to be able to undo
  485.                          * commands, but it's nonsense
  486.                          * to undo part of an insertion
  487.                          * so if in input mode don't.
  488.                          */
  489. #ifdef MDEBUG
  490.                         if (trace)
  491.                             fprintf(trace, "Call macpush, b %d %d %d\n", b[0], b[1], b[2]);
  492. #endif
  493.                         macpush(&b[1],maps == arrows);
  494. #ifdef MDEBUG
  495.                         if (trace)
  496.                             fprintf(trace, "return %d\n", c);    
  497. #endif
  498.                         return(c);
  499.                     }
  500.                     *q = getkey();
  501.                     q[1] = 0;
  502.                 }
  503.                 if (*p != *q)
  504.                     goto contin;
  505.             }
  506.             macpush(maps[d].mapto,maps == arrows);
  507.             c = getkey();
  508. #ifdef MDEBUG
  509.             if (trace)
  510.                 fprintf(trace,"Success: push(%s), return %c",maps[d].mapto, c);
  511. #endif
  512.             return(c);    /* first char of map string */
  513.             contin:;
  514.         }
  515.     }
  516. #ifdef MDEBUG
  517.     if (trace)
  518.         fprintf(trace,"Fail: push(%s), return %c", &b[1], c);
  519. #endif
  520.     macpush(&b[1],0);
  521.     return(c);
  522. }
  523.  
  524. /*
  525.  * Push st onto the front of vmacp. This is tricky because we have to
  526.  * worry about where vmacp was previously pointing. We also have to
  527.  * check for overflow (which is typically from a recursive macro)
  528.  * Finally we have to set a flag so the whole thing can be undone.
  529.  * canundo is 1 iff we want to be able to undo the macro.  This
  530.  * is false for, for example, pushing back lookahead from fastpeekkey(),
  531.  * since otherwise two fast escapes can clobber our undo.
  532.  */
  533. macpush(st, canundo)
  534. char *st;
  535. int canundo;
  536. {
  537.     char tmpbuf[BUFSIZ];
  538.  
  539.     if (st==0 || *st==0)
  540.         return;
  541. #ifdef MDEBUG
  542.     if (trace)
  543.         fprintf(trace, "macpush(%s), canundo=%d\n",st,canundo);
  544. #endif
  545.     if ((vmacp ? strlen(vmacp) : 0) + strlen(st) > BUFSIZ)
  546.         error("Macro too long@ - maybe recursive?");
  547.     if (vmacp) {
  548.         strcpy(tmpbuf, vmacp);
  549.         if (!FIXUNDO)
  550.             canundo = 0;    /* can't undo inside a macro anyway */
  551.     }
  552.     strcpy(vmacbuf, st);
  553.     if (vmacp)
  554.         strcat(vmacbuf, tmpbuf);
  555.     vmacp = vmacbuf;
  556.     /* arrange to be able to undo the whole macro */
  557.     if (canundo) {
  558. #ifdef notdef
  559.         otchng = tchng;
  560.         vsave();
  561.         saveall();
  562.         inopen = -1;    /* no need to save since it had to be 1 or -1 before */
  563.         vundkind = VMANY;
  564. #endif
  565.         vch_mac = VC_NOCHANGE;
  566.     }
  567. }
  568.  
  569. #ifdef TRACE
  570. visdump(s)
  571. char *s;
  572. {
  573.     register int i;
  574.  
  575.     if (!trace) return;
  576.  
  577.     fprintf(trace, "\n%s: basWTOP=%d, basWLINES=%d, WTOP=%d, WBOT=%d, WLINES=%d, WCOLS=%d, WECHO=%d\n",
  578.         s, basWTOP, basWLINES, WTOP, WBOT, WLINES, WCOLS, WECHO);
  579.     fprintf(trace, "   vcnt=%d, vcline=%d, cursor=%d, wcursor=%d, wdot=%d\n",
  580.         vcnt, vcline, cursor-linebuf, wcursor-linebuf, wdot-zero);
  581.     for (i=0; i<TUBELINES; i++)
  582.         if (vtube[i] && *vtube[i])
  583.             fprintf(trace, "%d: '%s'\n", i, vtube[i]);
  584.     tvliny();
  585. }
  586.  
  587. vudump(s)
  588. char *s;
  589. {
  590.     register line *p;
  591.     char savelb[1024];
  592.  
  593.     if (!trace) return;
  594.  
  595.     fprintf(trace, "\n%s: undkind=%d, vundkind=%d, unddel=%d, undap1=%d, undap2=%d,\n",
  596.         s, undkind, vundkind, lineno(unddel), lineno(undap1), lineno(undap2));
  597.     fprintf(trace, "  undadot=%d, dot=%d, dol=%d, unddol=%d, truedol=%d\n",
  598.         lineno(undadot), lineno(dot), lineno(dol), lineno(unddol), lineno(truedol));
  599.     fprintf(trace, "  [\n");
  600.     CP(savelb, linebuf);
  601.     fprintf(trace, "linebuf = '%s'\n", linebuf);
  602.     for (p=zero+1; p<=truedol; p++) {
  603.         fprintf(trace, "%o ", *p);
  604.         getline(*p);
  605.         fprintf(trace, "'%s'\n", linebuf);
  606.     }
  607.     fprintf(trace, "]\n");
  608.     CP(linebuf, savelb);
  609. }
  610. #endif
  611.  
  612. /*
  613.  * Get a count from the keyed input stream.
  614.  * A zero count is indistinguishable from no count.
  615.  */
  616. vgetcnt()
  617. {
  618.     register int c, cnt;
  619.  
  620.     cnt = 0;
  621.     for (;;) {
  622.         c = getkey();
  623.         if (!isdigit(c))
  624.             break;
  625.         cnt *= 10, cnt += c - '0';
  626.     }
  627.     ungetkey(c);
  628.     Xhadcnt = 1;
  629.     Xcnt = cnt;
  630.     return(cnt);
  631. }
  632.  
  633. /*
  634.  * fastpeekkey is just like peekkey but insists the character come in
  635.  * fast (within 1 second). This will succeed if it is the 2nd char of
  636.  * a machine generated sequence (such as a function pad from an escape
  637.  * flavor terminal) but fail for a human hitting escape then waiting.
  638.  */
  639. fastpeekkey()
  640. {
  641.     int trapalarm();
  642.     int (*Oint)();
  643.     register int c;
  644.  
  645.     /*
  646.      * If the user has set notimeout, we wait forever for a key.
  647.      * If we are in a macro we do too, but since it's already
  648.      * buffered internally it will return immediately.
  649.      * In other cases we force this to die in 1 second.
  650.      * This is pretty reliable (VMUNIX rounds it to .5 - 1.5 secs,
  651.      * but UNIX truncates it to 0 - 1 secs) but due to system delays
  652.      * there are times when arrow keys or very fast typing get counted
  653.      * as separate.  notimeout is provided for people who dislike such
  654.      * nondeterminism.
  655.      */
  656. #ifdef MDEBUG
  657.     if (trace)
  658.         fprintf(trace,"\nfastpeekkey: ",c);
  659. #endif
  660.     Oint = signal(SIGINT, trapalarm);
  661.     if (value(TIMEOUT) && inopen >= 0) {
  662.         signal(SIGALRM, trapalarm);
  663. #ifdef MDEBUG
  664.         alarm(10);
  665.         if (trace)
  666.             fprintf(trace, "set alarm ");
  667. #else
  668.         alarm(1);
  669. #endif
  670.     }
  671.     CATCH
  672.         c = peekkey();
  673. #ifdef MDEBUG
  674.     if (trace)
  675.         fprintf(trace,"[OK]",c);
  676. #endif
  677.         alarm(0);
  678.     ONERR
  679.         c = 0;
  680. #ifdef MDEBUG
  681.     if (trace)
  682.         fprintf(trace,"[TIMEOUT]",c);
  683. #endif
  684.     ENDCATCH
  685. #ifdef MDEBUG
  686.     if (trace)
  687.         fprintf(trace,"[fpk:%o]",c);
  688. #endif
  689.     signal(SIGINT,Oint);
  690.     return(c);
  691. }
  692.  
  693. trapalarm() {
  694.     alarm(0);
  695.     if (vcatch)
  696.         longjmp(vreslab,1);
  697. }
  698.